#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <unistd.h>

#include "socket_pthread.h"

int main(int argc,char **argv)
{
    /*创建套接字相关变量*/
    int main_skt,new_skt;
    struct sockaddr_in server_addr,client_addr;
    unsigned short portnum=0x8888;
    int addrsize;
    /*辅助变量*/
    int  num=0;
    char buffer[100]={0};
    int  recbyte;
    pthread_t  thread_list[10];
    /*      */
    printf("Hellp,welcome to my server!\r\n");
    
    /*
    AF_INET IPV4
    AF_INET IPV6
    AF_UNIX 本机通讯

    SOCK_STREAM  TCP流
    SOCK_DGRAM   UDP流

    第三个参数是协议 0=自动选择
    */
    /*创建套接字，用于监听、创建新的套接字（accept)*/
    main_skt=socket(AF_INET,SOCK_STREAM,0);
    if(-1==main_skt){
        printf("socket fail!\r\n");
        return -1;
    }
    printf("socker ok!\r\n");
    /*配置IP地址及端口号*/
    bzero(&server_addr,sizeof(struct sockaddr_in));
    addrsize = sizeof(struct sockaddr_in);
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY本机IP   主机字节顺序转化为网络字节顺序
    server_addr.sin_port=htons(portnum);
    /*将地址信息绑定到套接字*/
    if(-1 == bind(main_skt,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))){
        printf("bind fail!\r\n");
        return -1;
    }
    printf("bind ok\r\n");
    /*开始监听,监听只是告诉内核：最大缓存队列长度，并不会阻塞
      注意！并不是最大连接数！
      当服务器繁忙，来不及accept的时候，先完成三次握手，放入缓存队列。
      accept发生在三次握手之后。
    */
    if(-1==listen(main_skt,2)){
        printf("listen fail!\r\n");
        return -1;
    }
    printf("listen ok\r\n");
    /*开始阻塞，等待客户端的链接*/
    /*注意主机若异常中断，则监听的端口还来不及释放，需要等待一段时间，让操作系统处理*/
    while(1) {
    // ACCEPT:
        new_skt = accept(main_skt,(struct sockaddr *__restrict)(&client_addr),&addrsize);
        if(-1==new_skt){
            printf("accept fail\r\n");
            close(new_skt);
            // goto ACCEPT;
            return -1;
        }
        printf("accept ok \r\n Server start get connect from %#x:%#x\r\n",ntohl(client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
        socket_pthread_creat(&thread_list[num],new_skt);
        /*此处有一个问题就是，thread虽然创建了，但还未调度起来，就有一个新的客户端接入，new_skt会被覆盖
          立马复制到线程的栈区就可以啦！
        */
        num++;
    }
    close(new_skt);
    close(main_skt);
    return 0;
}
